package com.zsy.provider.config.exception;

import com.alibaba.fastjson.JSON;
import com.zsy.base.bean.DemoResult;
import com.zsy.base.constant.Constants;
import com.zsy.base.constant.ResponseMessageConstant;
import com.zsy.common.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.error.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @program: my-springcloud
 * @description: 自定义续签token,如果采用续签，就不要用AuthExceptionEntryPoint
 * @author: zhaoshouyun
 * @create: 2020-04-27 10:43
 **/
@Slf4j
@Component
public class CustomOAuth2AuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {
    @Value("${auth.clientId}")
    private String clientId;

    @Value("${auth.clientSecret}")
    private String clientSecret;

    @Value("${auth.cookieDomain}")
    private String cookieDomain;

    @Value("${auth.cookieMaxAge}")
    private int cookieMaxAge;

    private OAuth2ExceptionRenderer exceptionRenderer = new DefaultOAuth2ExceptionRenderer();
    @Autowired
    private BaseOAuth2ProtectedResourceDetails baseOAuth2ProtectedResourceDetails;
    private WebResponseExceptionTranslator<?> exceptionTranslator = new DefaultWebResponseExceptionTranslator();
    @Autowired
    RestTemplate restTemplate;

    @Autowired
    RedisUtils redisUtils;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        try {
            //解析异常，如果是401则处理
            ResponseEntity<?> result = exceptionTranslator.translate(authException);
            if (result.getStatusCode() == HttpStatus.UNAUTHORIZED) {
                MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
                formData.add("client_id", clientId);
                formData.add("client_secret", clientSecret);
                formData.add("grant_type", "refresh_token");
                /*Cookie[] cookies=request.getCookies();
                for(Cookie coo:cookies){
                    if(coo.getName().equals("refresh_token")){
                        formData.add("refresh_token", coo.getValue());
                    }
                }*/
                Object o = redisUtils.get(Constants.REDIS_TOKEN_KEY);
                if (o != null){
                    Map map = (Map)o;
                    formData.add("refresh_token", map.get("refresh_token") != null ? map.get("refresh_token").toString() :null);
                }
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                Map map = null;
                try{
                    map = restTemplate.exchange(baseOAuth2ProtectedResourceDetails.getAccessTokenUri(), HttpMethod.POST,
                            new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class).getBody();

                }catch (Exception e){
                   // result = enhanceResponse(result, authException);
                    Throwable cause = authException.getCause();
                    if(cause instanceof InvalidTokenException) {
                        response.getWriter().write(JSON.toJSONString(DemoResult.FAIL(ResponseMessageConstant.OAUTH_TOKEN_ILLEGAL)));
                    }else{
                        response.getWriter().write(JSON.toJSONString(DemoResult.FAIL(ResponseMessageConstant.OAUTH_TOKEN_MISSING)));
                    }
                    response.flushBuffer();
                    return;
                }
                              //如果刷新异常,则坐进一步处理
                if(map.get("error")!=null){
                    // 返回指定格式的错误信息
                    response.setStatus(401);
                    response.setHeader("Content-Type", "application/json;charset=utf-8");
                    DemoResult description = DemoResult.FAIL(map.get("error_description").toString());
                    response.getWriter().print(JSON.toJSONString(description));
                    response.getWriter().flush();
                    //如果是网页,跳转到登陆页面
                    //response.sendRedirect("login");
                }else{

                    //如果刷新成功则存储cookie并且跳转到原来需要访问的页面
                  /*  for(Object key:map.keySet()){
                        Cookie cookie = new Cookie(key.toString(),map.get(key).toString());
                        cookie.setMaxAge(cookieMaxAge);
                        response.addCookie(cookie);
                    }*/
                    log.info("刷新token成功！uri={}",request.getRequestURI());
                    redisUtils.set(Constants.REDIS_TOKEN_KEY,map);
                    request.getRequestDispatcher(request.getRequestURI()).forward(request,response);
                }
            }else{
                //如果不是401异常，则以默认的方法继续处理其他异常
                super.commence(request,response,authException);
            }
        } catch (IOException e) {
            throw e;
        }
        catch (RuntimeException e) {
            throw e;
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}
